package com.fingard.dsp.tcpserver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.diagnostics.LogHelper;
import com.fingard.dsp.DSPCenter;
import com.fingard.dsp.DSPSet;
import com.fingard.dsp.Transmit;
import com.fingard.dsp.bank.DealDirectBank;
import com.fingard.dsp.bank.DealTransSeq;
import com.fingard.dsp.bank.helpers.FileType;
import com.fingard.dsp.bank.reqrespobj.ReqRespHeader;
import com.fingard.io.FileHelper;
import com.fingard.text.StringHelper;
import com.fingard.text.XmlHelper;
import com.fingard.util.DateHelper;
import com.fingard.util.secret.salary.FieldHiddenUtil;
import com.fingard.xml.XmlTextReader;

public class ThreadSocket implements Runnable {

    private RequestNIO bizObj;


    public ThreadSocket(RequestNIO p_bizO) {
        bizObj = p_bizO;
    }

    public void run() {
        try {
            doRequest(bizObj);
        } catch (Exception ex) {
            ex.printStackTrace();

        }

    }

    private static AtomicInteger concurrentNum = new AtomicInteger();
    private static int maxConcurrent = 0;
    private static Date maxHappenedTime = new Date();

    private void doRequest(RequestNIO p_bizO) {

        int tmpConcurrentNum = concurrentNum.incrementAndGet();
        if (tmpConcurrentNum > maxConcurrent) {
            maxConcurrent = tmpConcurrentNum;
            maxHappenedTime = new Date();
            System.out.println(Format.DateTimeSSSFormat.format(maxHappenedTime) + " 请求" + p_bizO.seqIDInner + "当前并发数：" + tmpConcurrentNum);
        }
        SocketReceiver tmpReceiver = p_bizO.reqSocketReceiver;
        DataOutputStream tmpRespOutput = null;
        DataInputStream tmpReqInput = null;
        String tmpRespBody = "";
        ReqRespHeader tmpHeader = new ReqRespHeader();
        tmpHeader.bankCode = "";
        tmpHeader.transType = "";
        p_bizO.sbLog.append(Format.DateTimeSSSFormat.format(p_bizO.connTime) + " " + p_bizO.seqIDInner + " 0.开始接收\r\n");

        try {
            tmpReqInput = new DataInputStream(tmpReceiver.socketClient.getInputStream());
            //byte[] tmpBytesRd = new byte[2048];//2K
            tmpReceiver.reqBytes = new byte[2048];//2K
            //int tmpOffSet = 0;
            //int tmpContentLength = -1;
            //int tmpContentStartIndex = -1;
            boolean isContinue = true;
            while (isContinue) {

                int tmpReadLen = tmpReqInput.read(tmpReceiver.reqBytes, tmpReceiver.receiveOffSet, tmpReceiver.reqBytes.length - tmpReceiver.receiveOffSet);
                if (tmpReadLen <= 0) {
                    break;
                }
                tmpReceiver.readedLength += tmpReadLen;
                tmpReceiver.receiveOffSet += tmpReadLen;
                tmpReceiver.getHeader(tmpHeader);
                
                if (tmpReceiver.contentLength < 0 || tmpReceiver.contentStartIndex < 0){
                    if (tmpReceiver.isCipherSocket == false && tmpReceiver.isSyncFile == false && tmpReceiver.receiveOffSet > 100){
                    	tmpRespBody = "未知的通讯头部：" + new String(tmpReceiver.reqBytes, 0, tmpReceiver.receiveOffSet, tmpReceiver.charsetName);
                    	tmpReceiver.contentStartIndex = -1;
                    	isContinue = false;
                    	break;
                    }
                }

                if (tmpReceiver.contentLength > 0 && tmpReceiver.contentStartIndex > 0) {
                    if(tmpReceiver.isSyncFile){//文件同步
                    	if(StringHelper.isNullOrEmpty(tmpReceiver.oriFilePath)){
                    		tmpReceiver.syncCode = "-1";
                    		tmpReceiver.syncMsg = "文件传输无文件路径";
                    		isContinue = false;
                            break;
                    	}
                    	if(tmpReceiver.saveFile == null){//第一次写入
                    		tmpReceiver.openSaveFile(tmpHeader);
                    		if((tmpReceiver.receiveOffSet-tmpReceiver.contentStartIndex) > 0){
                    			tmpReceiver.saveFileStream.write(tmpReceiver.reqBytes, tmpReceiver.contentStartIndex, tmpReceiver.receiveOffSet-tmpReceiver.contentStartIndex);
                        		if(tmpReceiver.contentLength>102400){//扩大缓冲区
                        			tmpReceiver.reqBytes = new byte[51200];//50K
                        		}else if(tmpReceiver.contentLength>40960){//扩大缓冲区
                        			tmpReceiver.reqBytes = new byte[20480];//20K
                        		}else if((tmpReceiver.contentLength + tmpReceiver.contentStartIndex)>tmpReceiver.reqBytes.length){//扩大缓冲区
                        			tmpReceiver.reqBytes = new byte[5120];//5K
                        		}
                    		}
                    	}else{//后续写入
                    		tmpReceiver.saveFileStream.write(tmpReceiver.reqBytes, 0, tmpReceiver.receiveOffSet);
                    	}
                    	tmpReceiver.receiveOffSet = 0;//重置字节接收
                    }else{
                    	if (tmpReceiver.reqBytes.length < tmpReceiver.contentLength + tmpReceiver.contentStartIndex) {
                            byte[] tmpUnionInfo = new byte[tmpReceiver.contentLength + tmpReceiver.contentStartIndex];//一次性分配内存
                            System.arraycopy(tmpReceiver.reqBytes, 0, tmpUnionInfo, 0, tmpReceiver.receiveOffSet);
                            tmpReceiver.reqBytes = null;
                            tmpReceiver.reqBytes = tmpUnionInfo;
                        }
                    }

                    int tmpToReadLen = tmpReceiver.contentLength + tmpReceiver.contentStartIndex - tmpReceiver.readedLength;
                    if (tmpToReadLen == 0) {//完成
                    	tmpReceiver.isCompleted = true;
                    	tmpReceiver.syncCode = "0";
                		tmpReceiver.syncMsg = "已保存"+tmpReceiver.fileType+"类型文件："+tmpReceiver.oriFilePath+"至"+tmpReceiver.trgFilePath+"完成";
                    	isContinue = false;
                        break;
                    }else if(tmpToReadLen < 0){//结束
                    	tmpReceiver.syncCode = "-1";
                    	int expectLen = tmpReceiver.contentLength + tmpReceiver.contentStartIndex;
                    	int actualLen = tmpReceiver.readedLength-tmpReceiver.contentStartIndex;
                		tmpReceiver.syncMsg = "实际接收总字节数"+tmpReceiver.readedLength+"与预期"+expectLen+"不符，其中实际接收内容字节数"+actualLen+"，预期内容字节数"+tmpReceiver.contentLength;
                    	isContinue = false;
                        break;
                    }
                }else if (tmpReceiver.contentLength == 0){
                	isContinue = false;
                    break;
                }
            }
            if(tmpReceiver.saveFileStream!=null){
            	tmpReceiver.saveFileStream.close();
            	tmpReceiver.saveFileStream = null;
            }
            p_bizO.recCompleteTime = new Date();
            //StringBuilder tmpSbLog = new StringBuilder();


            //String tmpStrReq = new String(tmpReceiver.reqBytes,tmpReceiver.contentStartIndex,tmpReceiver.contentLength,tmpReceiver.charsetName);
            //MyHandler tmpHandler = new MyHandler();
            boolean isRtnFileBytes = false;
            String rtnFilePath="";
            if(tmpReceiver.isSyncFile){
            	tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>"+tmpReceiver.syncCode+"</RespCode><RespInfo>"+XmlHelper.encode(tmpReceiver.syncMsg)+"</RespInfo></TransParam></TransResp></ATSYH>";
            }else if("getfile".equals(tmpReceiver.action)){
            	String oriFile = DSPSet.replaceFilePath(tmpReceiver.oriFilePath);
            	String errmsg="";
            	if(FileType.dataFile.toLowerCase().equals(tmpReceiver.fileType)){
            		oriFile = StringHelper.trimEndFileSp(FGBiz.dspCenter.dspSet.dataDirPath) + File.separator + StringHelper.trimStartFileSp(oriFile);
            	}
            	if(StringHelper.hasAnyChar(oriFile)){
        			if(FileHelper.existFile(oriFile)){
        				isRtnFileBytes = true;
        				rtnFilePath = oriFile;
        			}else{
        				errmsg="文件"+tmpReceiver.oriFilePath+"不存在";
        			}
        		}else{
        			errmsg="请求参数文件路径为空";
        		}
            	if(!isRtnFileBytes){
            		tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>"+XmlHelper.encode(errmsg)+"</RespInfo></TransParam></TransResp></ATSYH>";
            	}
            }else if (tmpReceiver.contentStartIndex >= 0) {
                try {
                    String tmpStrReq = new String(tmpReceiver.reqBytes, tmpReceiver.contentStartIndex, tmpReceiver.contentLength, tmpReceiver.charsetName);
                    p_bizO.sbLog.append(Format.DateTimeSSSFormat.format(p_bizO.recCompleteTime) + " 1.接收ATS的报文：\r\n");
//                    p_bizO.sbLog.append(tmpStrReq);
                    p_bizO.sbLog.append(FieldHiddenUtil.wordHiddle(tmpStrReq,new String[]{"DecryptKey"}));
                    p_bizO.sbLog.append("\r\n\r\n");
                    //StringReader tmpStrReader = new StringReader(tmpStrReq);
                    //InputSource inSource = new InputSource(tmpStrReader);

                    //DocumentBuilderFactory tmpFactory = DocumentBuilderFactory.newInstance();
                    //DocumentBuilder tmpDomBuilder = tmpFactory.newDocumentBuilder();
                    //Document tmpRetDoc = tmpDomBuilder.parse(inSource);

					/*
                    ByteArrayInputStream byteStream = new ByteArrayInputStream(tmpReceiver.reqBytes, tmpReceiver.contentStartIndex, tmpReceiver.contentLength);
			        
			        InputStreamReader streamReader = new InputStreamReader(byteStream, tmpReceiver.charsetName);
			        InputSource inSource = new InputSource(streamReader);
			        
					DocumentBuilderFactory tmpFactory = DocumentBuilderFactory.newInstance();
					DocumentBuilder tmpDomBuilder = tmpFactory.newDocumentBuilder();
					*/
                    StringBuilder sbReq = new StringBuilder();
                    sbReq.append(tmpStrReq);
                    XmlTextReader xmlReader = new XmlTextReader(sbReq);
                    tmpHeader = DSPCenter.getReqRespHeader(xmlReader);
                    boolean isChecked = false;
                    if (FGBiz.dspCenter.enableCheckTransSeqID && !StringHelper.isNullOrEmpty(tmpHeader.transTime)) {
                    	Date transTime = null;
                    	// 兼容TransTime格式为：yyyyMMddHH:mm:ss
                    	if (tmpHeader.transTime.indexOf(" ") > 0) {
                    		transTime = Format.DateTimeFormat.parse(tmpHeader.transTime);
                    	} else {
                    		transTime = Format.DateTime1Format.parse(tmpHeader.transTime);
                    	}
                    	
                        Date currDate = new Date();
                        if (Math.abs(DateHelper.getDifferMins(transTime, currDate)) > DealTransSeq.maxStep) {
                            tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>本次请求时间距离当前时间太长，请求已过期！</RespInfo></TransParam></TransResp></ATSYH>";
                        } else {
                            isChecked = true;
                        }
                    } else {
                        isChecked = true;
                    }
                    if (isChecked) {
                    	boolean isUniqueTransSeq = true;
                        if (FGBiz.dspCenter.enableCheckTransSeqID) {
                        	if(!DealTransSeq.addTransSeq(tmpHeader.transSeqID, tmpHeader.transTime)){
                        		isUniqueTransSeq = false;
                        		tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>指令流水号重复</RespInfo></TransParam></TransResp></ATSYH>";
                        	}
                        }  
                        if(isUniqueTransSeq){
                            Transmit tmpTransmit = new Transmit(p_bizO, FGBiz.dspCenter.rootDirPath);
                            if (tmpTransmit.isTransmit(tmpHeader)) {
                                tmpRespBody = tmpTransmit.doTransmit(p_bizO.reqSocketReceiver.getContentBytes());
                            } else {
                                DealDirectBank tmpDealDirect = new DealDirectBank(tmpStrReq);
                                tmpRespBody = tmpDealDirect.dealDirectTrans(p_bizO, tmpHeader, xmlReader);
                            }
                        }
                    }
                /*
				//step1： 获得SAX解析器工厂实例  
		        SAXParserFactory factory = SAXParserFactory.newInstance();  
		          
		        //step2: 获得SAX解析器实例  
		        SAXParser parser = factory.newSAXParser();  
		        //step3: 开始进行解析  
		        ByteArrayInputStream byteStream = new ByteArrayInputStream(tmpReceiver.reqBytes, tmpReceiver.contentStartIndex, tmpReceiver.contentLength);
		        
		        InputStreamReader streamReader = new InputStreamReader(byteStream, tmpReceiver.charsetName);
		        InputSource inSource = new InputSource(streamReader);
		        parser.parse(inSource, tmpHandler);
		        */
                } catch (Exception e2) {
                	p_bizO.sbLog.append(LogHelper.getStackTrace(e2) + "\r\n");
                    tmpRespBody = e2.toString();//+ "\r\n" + e2.getLocalizedMessage()
                }catch(Throwable t3){
                	p_bizO.sbLog.append(LogHelper.getStackTrace(t3) + "\r\n");
                	tmpRespBody = t3.toString();//+ "\r\n" + t3.getLocalizedMessage()
                }
            }
            byte[] tmpBytesResp = null;
            if(isRtnFileBytes){
            	File tmpFile = new File(rtnFilePath);
            	Long filelength = tmpFile.length();
            	int filelenInt = filelength.intValue();
            	String tmpFileLen = String.format("% 8d", filelenInt);
                String tmpRespHead = "file-length:" + tmpFileLen + "\r\n\r\n";
                byte[] tmpBytesHead = tmpRespHead.getBytes(tmpReceiver.charsetName);

                tmpBytesResp = new byte[tmpBytesHead.length + filelenInt];
                System.arraycopy(tmpBytesHead, 0, tmpBytesResp, 0, tmpBytesHead.length);
                try {  
                    FileInputStream in = new FileInputStream(tmpFile);
                    in.read(tmpBytesResp,tmpBytesHead.length,filelenInt);
                    in.close();
                } catch (FileNotFoundException e) {
                	isRtnFileBytes = false;
                	tmpRespBody = LogHelper.getStackTrace(e);
                	p_bizO.sbLog.append(LogHelper.getStackTrace(e));
                } catch (IOException e) {
                	isRtnFileBytes = false;
                	tmpRespBody = LogHelper.getStackTrace(e);
                	p_bizO.sbLog.append(LogHelper.getStackTrace(e));
                }
                
            }
            if(!isRtnFileBytes){
            	if(tmpRespBody.startsWith("java") || !tmpRespBody.contains("<")){
                	tmpRespBody = "<ATSYH><TransResp><TransParam><RespCode>-1</RespCode><RespInfo>"+XmlHelper.encode(tmpRespBody)+"</RespInfo></TransParam></TransResp></ATSYH>";
                }
                if (tmpReceiver.readedLength == 0) {
                    //F5等设备的监测
                    tmpReqInput.close();
                    tmpReqInput = null;
                    tmpReceiver.socketClient.close();
                    return;
                }
                byte[] tmpBytesBody = tmpRespBody.getBytes(tmpReceiver.charsetName);

                String tmpStrLen = String.format("% 8d", tmpBytesBody.length);

                String tmpRespHead = "Content-Length:" + tmpStrLen + "\r\n";
                byte[] tmpBytesHead = tmpRespHead.getBytes(tmpReceiver.charsetName);

                tmpBytesResp = new byte[tmpBytesHead.length + tmpBytesBody.length];
                System.arraycopy(tmpBytesHead, 0, tmpBytesResp, 0, tmpBytesHead.length);
                System.arraycopy(tmpBytesBody, 0, tmpBytesResp, tmpBytesHead.length, tmpBytesBody.length);
            }
            


            tmpRespOutput = new DataOutputStream(tmpReceiver.socketClient.getOutputStream());
			/*
			String tmpFileName = FGBiz.dspCenter.rootDirPath+File.separator+ "Simulate"+File.separator + tmpHandler.bankCode + "_" + tmpHandler.transType + "resp.xml";
			File tmpFile = new File(tmpFileName);
			if(tmpFile.exists())
			{
				tmpRespBody = FileHelper.readToString(tmpFile, "gb2312").replace("{$ReqSeqID}",tmpHandler.reqSeqID);
			}
			else{
				tmpRespBody = "<ATSYH><TransResp><BankCode>"+tmpHandler.bankCode+"</BankCode><TransType>"+tmpHandler.transType+"</TransType><TransSeqID>"+tmpHandler.transSeqID+"</TransSeqID><TransParam><RespCode>-1</RespCode><RespInfo>未知的请求</RespInfo></TransParam></TransResp></ATSYH>";
			}
			*/
            

            tmpRespOutput.write(tmpBytesResp);

            tmpReqInput.close();
            tmpReqInput = null;
            tmpRespOutput.close();
            tmpRespOutput = null;
            //System.out.println("处理完"+p_receiver.seqIDInner);


        } catch (Exception e) {
            p_bizO.sbLog.append(LogHelper.getStackTrace(e) + "\r\n");
            e.printStackTrace();
            //System.out.println(e.toString());
            //log.error(e);

        } catch(Throwable t2){
        	p_bizO.sbLog.append(LogHelper.getStackTrace(t2) + "\r\n");
        	t2.printStackTrace();
        }
        finally {

            try {

                if (tmpReqInput != null) {
                    tmpReqInput.close();
                }
                if (tmpRespOutput != null) {
                    tmpRespOutput.close();
                }
                tmpReceiver.socketClient.close();
                if(tmpReceiver.saveFileStream!=null){
                	tmpReceiver.saveFileStream.close();
                }
                
                tmpConcurrentNum = concurrentNum.decrementAndGet();
                if (tmpConcurrentNum == 0) {
                    Date tmpTimeNow = new Date();
                    long tmpMilSeconds = tmpTimeNow.getTime() - maxHappenedTime.getTime();
                    long tmpSeconds = tmpMilSeconds / 1000;
                    if (tmpSeconds >= 60) {
                        maxConcurrent = 0;
                        System.out.println("请求" + p_bizO.seqIDInner + "当前并发数：" + tmpConcurrentNum);
                    }
                }

            } catch (Exception e) {
                p_bizO.sbLog.append(LogHelper.getStackTrace(e) + "\r\n");
            }

        }

        try {
            Date tmpTimeNow = new Date();
            if(tmpReceiver.isSyncFile){
            	p_bizO.sbLog.append(Format.DateTimeSSSFormat.format(tmpTimeNow) + " " + p_bizO.seqIDInner + " 4.返回客户端的报文：\r\n");
            }else{
            	p_bizO.sbLog.append(Format.DateTimeSSSFormat.format(tmpTimeNow) + " 4.返回ATS的报文：\r\n");	
            }
            
            p_bizO.sbLog.append(tmpRespBody);
            p_bizO.sbLog.append("\r\n");
			
			/*
			String tmpStrLogSeq = String.format("%04d", p_bizO.seqIDInner);
			String tmpDateDir = Format.DateForLogFormat.format(tmpTimeNow).replace("-", File.separator);
			String tmpSubFileName = "BankLogs"+File.separator+tmpDateDir+File.separator+tmpHeader.bankCode+File.separator+tmpHeader.transType+"_"+Format.DateTime14Format.format(tmpTimeNow)+"_"+tmpStrLogSeq+".txt";
			String tmpLogFile = FGBiz.dspCenter.bankLogsDirPath+File.separator+tmpSubFileName;
			FileHelper.writeFile(tmpLogFile, p_bizO.sbLog);
			*/
            if(tmpReceiver.isSyncFile){
            	LogHelper.writeBankLogByHour(tmpTimeNow, "", tmpHeader, p_bizO.sbLog);
            }else{
            	LogHelper.writeBankLog(p_bizO.seqIDInner, p_bizO.connTime, tmpTimeNow, "",tmpHeader, p_bizO.sbLog);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
